#include "HTTPTransport.h"
#include "MsnConnection.h"
#include "Util.h"
#include "MsnDef.h"
#include "MsnCommand.h"

wxString HTTPTransport::GetSessionID(const wxString& headers)
{
	int start = headers.find(_T("SessionID="));
    int end = headers.find(_T(";"),start);

    wxString sessionID = headers.SubString(start+10, end-1).Trim(false).Trim(true);
    return sessionID;
}

wxString HTTPTransport::GetGatewayIP(const wxString& headers)
{
	int start = headers.find(_T("GW-IP="));
    int end = headers.find(_T(";"),start);

	if(end == -1){
		end = headers.find(_T("\r\n"),start);
	}

    wxString sessionID = headers.SubString(start+6, end-1).Trim(false).Trim(true);
    return sessionID;
}

int HTTPTransport::GetContentLength(const wxString& headers)
{
    wxString length =StringUtil::SubString(headers, _T("Content-Length:"), _T("\r\n"));
	return StringUtil::ToLong(length);	
}


HTTPTransport::HTTPTransport()
{
	gatewayIP = MSN_HTTP_SERVER_ADDRESS;
	openAction = true;
}

void* HTTPTransport::Entry()
{
	DEBUG(_T("HTTPTransport thread start: ") + wxString::Format(_T("%d"),this->GetId()));

/*
    wxIPV4address addr;
    addr.Hostname(_T("gateway.messenger.hotmail.com"));
    addr.Service(80);

    ((wxSocketClient*)socket)->Connect(addr, true);

    if (!socket->IsConnected()){
		
       return 0;
	}
*/

    bool connected = this->Open();

	if(!connected){
		connection->ConnectionFailed();
        return 0;
	}


	socket->SetTimeout(1);

	while (!closed && !TestDestroy()){

		char tmp;
		if(socket->Peek(&tmp, 1).LastCount() > 0){
			

			wxString headers = ReadHeader();

			//gatewayIP = response.GetGatewayIP();
			serverAddress = GetGatewayIP(headers);
			sessionID = GetSessionID(headers);

			int len = GetContentLength(headers);
			
			if(len > 0){
				char* buf = new char[len];
				ReadChunk(buf, len);	

				ProcessHttpBody(buf, len);
				
				delete[] buf;

				//DEBUG(_T("<<<") +response.header);
				//DEBUG(_T("<<<") +response.body);

				//connection->ProcessCommand(response.body.Trim(true));
			}

			if(closed || TestDestroy()){
				DEBUG(_T("connection closed "));

				connection->ConnectionClosed();
				break;
			}

			if(socket->Error()){
				DEBUG(wxString::Format(_T("socket error occured: %d "), socket->LastError()));
				connection->ConnectionBroken();
				break;
			}

		}else{
			//DEBUG(_T("poll"));
			HttpPost(_T("/gateway/gateway.dll?Action=poll&SessionID=") + sessionID, 
				_T(""));
		}
    }



    DEBUG(_T("HTTPTransport thread exit:")+ wxString::Format(_T("%d"),this->GetId()));
    return 0;
}

void HTTPTransport::ProcessHttpBody(char* buf, int len)
{
	DEBUG(_T("<<< HTTP Response \r\n ") + wxString(buf, wxConvUTF8, len));

	wxMemoryBuffer lineBuf;
    for(int i=0; i<len; i++){
        char c = buf[i];
		//skip 13
		if(c == 13){
            continue;
		}
		if(c == 10){
			wxString cmdLine((char*)lineBuf.GetData(), wxConvUTF8, lineBuf.GetDataLen());
			MsnCommand* cmd = MsnCommandFactory::Get().CreateCommand(cmdLine);

			if(cmd == NULL){
				DEBUG(_T("undefined command: ") + cmdLine);
				continue;
			}
	
			MsnCommandWrapper wrapper(cmd);	

			if(wrapper.IsPayloadCommand()){
				int len = wrapper.GetPayloadLength();
				wrapper.GetPayloadBuffer().AppendData(buf + i + 1, len);
				i += len;
			}

			connection->ProcessCommand(&wrapper);

			lineBuf = wxMemoryBuffer();
            continue;
		}

		lineBuf.AppendByte(c);
    }   
}


void HTTPTransport::SendData(void* data, unsigned int size)
{
//HttpPost(_T("http://gateway.messenger.hotmail.com/gateway/gateway.dll?Action=open&Server=NS&IP=messenger.hotmail.com"), 
//			 _T("VER 1 MSNP9 CVR0\r\n"));

	//wxString url = _T("http://") + serverAddress + _T("/gateway/gateway.dll?");

	wxString url = _T("/gateway/gateway.dll?");

	if(sessionID.IsEmpty()){
		url << _T("Action=open");
		url << _T("&Server=") << serverType;
		url << _T("&IP=")<<serverAddress;
	}else{
		url += _T("SessionID=") + sessionID;
	}

	wxString body = wxString((char*)data, wxConvUTF8, size);

	HttpPost(url, body);

}

void HTTPTransport::HttpPost(const wxString& url, const wxString& body)
{
	wxString header;

        //POST
    header += _T("POST ");
    header += url;
    header += _T(" HTTP/1.0\r\n");

        //Write host website name
	if(gatewayIP.IsEmpty()){
		header += _T("Host: gateway.messenger.hotmail.com\r\n");
	}else{
		header += _T("Host: ") +gatewayIP+ _T("\r\n");
	}

	header += _T("Accept: */*\r\n");
	header += _T("User-Agent: MSMSGS\r\n");
	header += _T("Connection: Keep-Alive\r\n");	
	
	header += _T("Content-Type: application/x-msn-messenger\r\n");

    //Write POST content length
    header += _T("Content-Length: ");
    header += wxString::Format(_T("%d"), body.Len());
    header += _T("\r\n");
	header += _T("\r\n");


	wxString request = header + body;

	socket->Write(WS2C(request), WSLEN(request));

	//socket->Write(WS2C(body), WSLEN(body)); 

	//DEBUG(_T(">>>") + request);

}

//TODO sometimes "100 continue" returns

wxString HTTPTransport::ReadHeader()
{
    wxMemoryBuffer buf;
	bool returnMet = false;
    char c;
    while(true){
        socket->Read(&c,1);
		buf.AppendByte(c);
		if(c == 10){
			if(returnMet){
				break;
			}else{
				returnMet = true;
			}
		}else if(c == 13){
            continue;
		}else{
			returnMet = false;
		} 

        if(socket == NULL || socket->Error()){
           break;
        }  
    }

    return wxString((char*)buf.GetData(), wxConvUTF8, buf.GetDataLen());
}

